package cn.bytest.netty.serialize;

import cn.bytets.rpc.api.serialize.ObjectInput;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.*;

public class GsonInput implements ObjectInput {

    private final BufferedReader reader;
    private Gson gson;

    public GsonInput(InputStream in) {
        this(new InputStreamReader(in));
    }

    public GsonInput(Reader reader) {
        this.reader = new BufferedReader(reader);
        this.gson = new GsonBuilder().
                registerTypeAdapter(Class.class, new JsonClassCodec())
                .create();
    }

    /**
     * Read boolean.
     *
     * @return boolean.
     * @throws IOException
     */
    @Override
    public boolean readBool() throws IOException {
        return read(boolean.class);
    }

    /**
     * Read byte.
     *
     * @return byte value.
     * @throws IOException
     */
    @Override
    public byte readByte() throws IOException {
        return read(byte.class);
    }

    /**
     * Read short integer.
     *
     * @return short.
     * @throws IOException
     */
    @Override
    public short readShort() throws IOException {
        return read(Short.class);
    }

    /**
     * Read integer.
     *
     * @return integer.
     * @throws IOException
     */
    @Override
    public int readInt() throws IOException {
        return read(Integer.class);
    }

    /**
     * Read long.
     *
     * @return long.
     * @throws IOException
     */
    @Override
    public long readLong() throws IOException {
        return read(Long.class);
    }

    /**
     * Read float.
     *
     * @return float.
     * @throws IOException
     */
    @Override
    public float readFloat() throws IOException {
        return read(Float.class);
    }

    /**
     * Read double.
     *
     * @return double.
     * @throws IOException
     */
    @Override
    public double readDouble() throws IOException {
        return read(Double.class);
    }

    /**
     * Read UTF-8 string.
     *
     * @return string.
     * @throws IOException
     */
    @Override
    public String readUTF() throws IOException {
        return read(String.class);
    }

    /**
     * Read byte array.
     *
     * @return byte array.
     * @throws IOException
     */
    @Override
    public byte[] readBytes() throws IOException {
        return readLine().getBytes();
    }

    /**
     * read object
     *
     * @return object
     * @throws IOException            if an I/O error occurs
     * @throws ClassNotFoundException if an ClassNotFoundException occurs
     */
    @Override
    public Object readObject() throws IOException, ClassNotFoundException {
        return readLine();
    }

    /**
     * read object
     *
     * @param cls object class
     * @return object
     * @throws IOException            if an I/O error occurs
     * @throws ClassNotFoundException if an ClassNotFoundException occurs
     */
    @Override
    public <T> T readObject(Class<T> cls) throws IOException, ClassNotFoundException {
        return read(cls);
    }

    private String readLine() throws IOException {
        String line = null;
        StringBuffer buffer = new StringBuffer();
        while ((line=reader.readLine())!=null){
            buffer.append(line);
        }
        line = buffer.toString();
        if (line == null || line.trim().length() == 0) {
            throw new EOFException();
        }
        return line;
    }

    private <T> T read(Class<T> cls) throws IOException {
        String json = readLine();
        return gson.fromJson(json, cls);
    }
}
